package com.wva.video.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.wva.minio.utils.MinIOUtils;
import com.wva.video.domain.dto.VideoSearchDTO;
import com.wva.video.domain.vo.VideoSearchItemDTO;
import com.wva.video.domain.vo.VideoSearchVO;
import com.wva.video.elasticsearch.document.VideoDocument;
import com.wva.video.service.VideoCoverService;
import com.wva.video.service.VideoSearchService;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: hong
 * @Date: 2025/3/2 15:57:36
 */
@Service
public class VideoSearchServiceImpl implements VideoSearchService {
    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Autowired
    MinIOUtils minIOUtils;
    @Autowired
    VideoCoverService videoCoverService;

    @Override
    public VideoSearchVO search(VideoSearchDTO videoSearchDTO) {
        //耗时计算
        long start = System.currentTimeMillis();

        //准备参数
        int pageNo = videoSearchDTO.getPageNo() - 1;
        Integer pageSize = videoSearchDTO.getPageSize();
        String sortBy = videoSearchDTO.getSortBy();
        Long categoryId = videoSearchDTO.getCategoryId();
        Double[] durationRange = videoSearchDTO.getDurationRange();
        LocalDateTime[] publishTimeRange = videoSearchDTO.getPublishTimeRange();
        SortOrder sortOrder = videoSearchDTO.getDesc() ? SortOrder.DESC : SortOrder.ASC;

        //视频状态必须是正常
        TermQueryBuilder statusBuilder = QueryBuilders.termQuery("status", 4);
        //分词、多字段搜索、复合查询：如果排序字段为null那么按关联度排序（默认排序）
        MultiMatchQueryBuilder contentBuilder = QueryBuilders.multiMatchQuery(
                videoSearchDTO.getContent(),
                "title",
                "description",
                "tags",
                "userNickname"
        );//TODO 补充分类，需要前端传过来分类id，前端先判断搜索内容包含哪个分类再把id传过来，加分器
        //时间范围
        RangeQueryBuilder publishTimeBuilder = QueryBuilders.rangeQuery("publishTime");
        if (publishTimeRange[0] != null) publishTimeBuilder.gte(publishTimeRange[0].toString());
        if (publishTimeRange[1] != null) publishTimeBuilder.lte(publishTimeRange[1].toString());
        //时长范围
        RangeQueryBuilder durationRangeBuilder = QueryBuilders.rangeQuery("duration");
        if (durationRange[0] != null) durationRangeBuilder.gte(durationRange[0]);
        if (durationRange[1] != null) durationRangeBuilder.lte(durationRange[1]);

        //拼接查询条件
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder
                .withFilter(statusBuilder)
                .withPageable(PageRequest.of(pageNo, pageSize));
        if (sortBy != null) {
            //按某个字段排序
            //分类限定，仅过滤
            if (categoryId != null) {
                nativeSearchQueryBuilder.withFilter(
                        QueryBuilders.termQuery("categoryId", categoryId)
                );
            }
            //拼接其它，不参与评分
            nativeSearchQueryBuilder
                    .withFilter(contentBuilder)
                    .withFilter(publishTimeBuilder)
                    .withFilter(durationRangeBuilder)
                    //拼接排序字段
                    .withSorts(SortBuilders.fieldSort(sortBy).order(sortOrder));
        } else {
            //按和搜索内容相关度排序
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            if (categoryId != null) {
                //分类限定，过滤+加分
                boolQueryBuilder.must(
                        QueryBuilders.termQuery("categoryId", categoryId)
                );
            }
            //拼接其它，参与评分
            boolQueryBuilder
                    .must(contentBuilder)
                    .filter(publishTimeBuilder)
                    .filter(durationRangeBuilder);
            nativeSearchQueryBuilder
                    .withQuery(boolQueryBuilder);

        }

        //高亮，在响应结果的highlight部分
        nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("title"));
        nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("description"));

        //响应
        SearchHits<VideoDocument> searchHits = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), VideoDocument.class);
        List<VideoSearchItemDTO> videoSearchItems = searchHits.getSearchHits().stream().map(searchHit -> {
            VideoSearchItemDTO videoSearchItemVO = BeanUtil.copyProperties(searchHit.getContent(), VideoSearchItemDTO.class);
            videoSearchItemVO.setHighlight(searchHit.getHighlightFields());
            //拼接视频封面地址
            String coverUrl = videoCoverService.getUrlByVideoId(videoSearchItemVO.getId());
            videoSearchItemVO.setCoverUrl(coverUrl);
            return videoSearchItemVO;
        }).collect(Collectors.toList());

        VideoSearchVO videoSearchVO = new VideoSearchVO();
        videoSearchVO.setTotal(searchHits.getTotalHits());
        videoSearchVO.setPages((long) Math.ceil(1.0*searchHits.getTotalHits() / pageSize));
        videoSearchVO.setList(videoSearchItems);
        videoSearchVO.setTimeConsume(System.currentTimeMillis() - start);
        return videoSearchVO;
    }
}
